package com.koron.system.staff.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.koron.bean.app.AppSimpleBean;
import com.koron.bean.base.Response;
import com.koron.bean.query.PageQuery;
import com.koron.bean.system.agent.vo.AgentUserVo;
import com.koron.bean.system.org.OrgVo;
import com.koron.bean.system.staff.Constant;
import com.koron.bean.system.staff.LangUserOrgConvert;
import com.koron.bean.system.staff.StaffBean;
import com.koron.bean.system.staff.dto.OutStaffBean;
import com.koron.bean.system.staff.dto.StaffBeanDto;
import com.koron.bean.system.staff.po.AppUserPo;
import com.koron.bean.system.staff.vo.AppUserVo;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.bean.util.JWTUtils;
import com.koron.bean.util.RedisUtils;
import com.koron.common.core.annocation.CasUser;
import com.koron.common.core.business.configsettings.utils.ConfigInfoTool;
import com.koron.common.core.business.langorguser.mapper.LangUserOrgConvertMapper;
import com.koron.common.core.business.system.MyRSAUtil;
import com.koron.common.core.business.system.SystemCacheUtil;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.common.core.util.FastJsonUtils;
import com.koron.common.core.util.HttpClient;
import com.koron.common.core.util.IpUtil;
import com.koron.common.core.util.verifyCode.IVerifyCodeGen;
import com.koron.common.core.util.verifyCode.SimpleCharVerifyCodeGenImpl;
import com.koron.common.core.util.verifyCode.VerifyCode;
import com.koron.system.staff.bean.WorkFlowUser;
import com.koron.system.staff.bean.dto.AppUserDto;
import com.koron.system.staff.bean.dto.ForgetPwDto;
import com.koron.system.staff.service.OutStaffService;
import com.koron.system.staff.service.StaffService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.ADOConnection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.Pattern;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName StaffController
 * @description
 * @Author zhouj
 * @Date 2021/7/6 14:27
 */
@Api(tags = "人员管理")
@RestController
@RequestMapping("/system/staff")
@RefreshScope
@Slf4j
@Validated
public class StaffController {

    @Autowired
    StaffService staffService;

    @Autowired
    OutStaffService outStaffService;

    @Value("${isNeedLogin}")
    private Boolean isNeedLogin;

    @Value("${sso.logout}")
    private String logoutUrl;

    @Value("${sso.casType:uma}")
    private String casType;

    @Value("${sso.iamLogoutUrl:null}")
    private String iamLogoutUrl;

    private static HttpClient httpClient = new HttpClient();

    @ApiOperation(value = "批量新增人员")
    @PostMapping("/batchInUpUser")
    public Response batchInUpUser(@CasUser @ApiIgnore EamUser user, @RequestBody List<AppUserPo> staffBeans) {
        return Response.success(staffService.batchInUpUser(user, staffBeans));
    }

    @ApiOperation(value = "新增人员")
    @PostMapping("/inUpUser")
    public Response inUpUser(@CasUser @ApiIgnore EamUser user,
                                @RequestParam(value = "staffBeanStr") String staffBeanStr,
                                @RequestParam(required = false, name = "photo") MultipartFile photo) {
        AppUserDto appUserDto = JSONObject.parseObject(staffBeanStr, AppUserDto.class);
        return Response.success("执行成功", staffService.insertUser(user, appUserDto, photo));
    }

    @SneakyThrows
    @ApiOperation(value = "修改人员")
    @PutMapping("/updateUser")
    public Response updateUser(@ApiIgnore @CasUser EamUser user, @RequestParam(value = "staffBeanStr") String staffBeanStr,
                                  @RequestParam(required = false, name = "photo") MultipartFile photo,
                                  @RequestParam(required = false, name = "deleteIds") String delPhotoId) {

        AppUserDto appUserDto = JSONObject.parseObject(staffBeanStr, AppUserDto.class);
        return Response.success(staffService.updateUser(user, appUserDto, photo, delPhotoId));
    }

    @SneakyThrows
    @ApiOperation(value = "修改人员(不带附件)")
    @PutMapping("/updateUserSimple")
    public Response updateUserSimple(@ApiIgnore @CasUser EamUser user, @RequestBody AppUserDto appUserDto) {
        return Response.success(staffService.updateUser(user, appUserDto, null, null));
    }

    @ApiOperation(value = "删除人员")
    @DeleteMapping("/delete")
    public Response delete(String id, String orgId) {
        return Response.success(staffService.deleteWithOrg(id, orgId));
    }

    @ApiOperation(value = "删除多组织下的人员")
    @DeleteMapping("/deleteWithOrg")
    public Response deleteWithOrg(String id, String orgId) {
        return Response.success(staffService.deleteWithOrg(id, orgId));
    }

    @ApiOperation(value = "批量删除人员")
    @DeleteMapping("/deleteIds")
    public Response deleteIds(@RequestParam("ids") List<String> ids,
                                 @RequestParam(value = "orgId", required = false) String orgId) {
        return Response.success(staffService.deleteIds(ids, orgId));
    }

    @ApiOperation(value = "通过组织查询人员列表(支持级联查询)(多组织返回多条数据)")
    @GetMapping("/queryStaffListByOrg")
    public Response queryStaffListByOrg(StaffBeanDto staffBeanDto,
                                           PageQuery pageQuery,
                                           @RequestParam(value = "isPage", required = false, defaultValue = "1") Integer isPage,
                                           @RequestParam(value = "cascadeQuery", required = false, defaultValue = "1") Integer cascadeQuery) {

        if (isPage == 1) {
            PageHelper.startPage(pageQuery.getPage(), pageQuery.getPageSize());
        }

        PageInfo<StaffBean> staffBeanPageInfo = new PageInfo<>(staffService.queryStaffListByOrg(cascadeQuery, staffBeanDto, pageQuery));

        return Response.success(staffBeanPageInfo.getList(), staffBeanPageInfo.getTotal());

    }

    @ApiOperation(value = "通过组织查询人员列表(支持级联查询)(多组织返回单条数据)")
    @GetMapping("/queryStaffListByOrgWithMerge")
    public Response<List<AppUserVo>> queryStaffListByOrgWithMerge(StaffBean staffBean,
                                                                  PageQuery pageQuery,
                                                                  @RequestParam(value = "isStsFlag", required = false, defaultValue = "false") Boolean isStsFlag,
                                                                  @RequestParam(value = "isPage", required = false, defaultValue = "1") Integer isPage,
                                                                  @RequestParam(value = "cascadeQuery", required = false, defaultValue = "1") Integer cascadeQuery) {

        if (isPage == 1) {
            PageHelper.startPage(pageQuery.getPage(), pageQuery.getPageSize());
        }

        PageInfo<AppUserVo> appUserVoPageInfo = new PageInfo<>(staffService.queryStaffListByOrgWithMerge(cascadeQuery, staffBean, pageQuery, isStsFlag));

        return Response.success(appUserVoPageInfo.getList(), appUserVoPageInfo.getTotal());
    }

    @ApiOperation(value = "通过账号查询用户的权限及基本信息")
    @GetMapping("/queryStaffInfo")
    public Response<EamUser> queryStaffInfo(String account) {
        return Response.success(staffService.queryStaffInfo(account));
    }

    @GetMapping("/getCurrUserInfo")
    @ApiOperation("通过token获取当前登录用户信息(请求头参数token)")
    public Response<EamUser> getCurrUserInfo(HttpServletRequest request, HttpServletResponse response) {

        String currDS = request.getHeader(Constant.DYNAMIC_DATA_SOURCE);
        //动态组织
        String currOrg = request.getHeader(Constant.DYNAMIC_AGENT_ORG);
        //动态领导
        String currLeader = request.getHeader(Constant.DYNAMIC_LEADER);
        //动态领导组织
        String currLeaderOrg = request.getHeader(Constant.DYNAMIC_LEADER_ORG);

        //是否本人
        Boolean self = true;
        String currAccount;
        //此时获取当前用户已经成为leader,应从token解析
        EamUser agent = ThreadLocalContext.get().getAgent();
        if (Objects.isNull(agent)) {
            currAccount = ThreadLocalContext.get().getAccount();
        } else {
            currAccount = agent.getAccount();
        }

        //当前token
        String token = request.getHeader(Constant.JWT_TOKEN);
        log.info("当前token:{}", token);
        //当前身份,需要对不同身份返回不同的人员信息
        EamUser agentUser = null;

        EamUser eamUser = staffService.queryStaffInfo(currAccount);

        Assert.isTrue(!Objects.isNull(eamUser), "不存在该账号信息:" + currAccount);

        //验证账号是否过期
        SystemCacheUtil.vertifyAccountExpire(eamUser);

        eamUser.setCurrDs(currDS);
        eamUser.setCurrOrg(currOrg);
        eamUser.setCurrLeader(currLeader);
        eamUser.setCurrLeaderOrg(currLeaderOrg);

        if (StringUtils.isNotEmpty(currLeader)) {
            //判断一下身份(是否本人)
            List<AgentUserVo> leaderUserVos = eamUser.getLeaderUserVos();
            if (CollectionUtils.isNotEmpty(leaderUserVos)) {
                List<String> leaderList = leaderUserVos.stream().map(AgentUserVo::getLeader).collect(Collectors.toList());
                //校验切换的leader账号  在代理领导列表中
                if (leaderList.contains(currLeader)) {
                    self = false;
                }
            }
            if (!self) {
                //非本人
                agentUser = staffService.queryAgentStaffInfo(currAccount);
                Objects.requireNonNull(agentUser, "被委托人不能为空");
                //缓存临时被委托人信息(配置的部分角色)
                agentUser.setCurrDs(currDS);
                agentUser.setCurrOrg(currLeaderOrg);
                SystemCacheUtil.cacheAgentLeaderInfo(agentUser, currAccount);
                agentUser.setAgent(eamUser);
            }
        }

        if (isNeedLogin) {
            String t_account = SystemCacheUtil.verifyToken(token);
            EamUser redisUser = SystemCacheUtil.getRedisUser(t_account);
            if (Objects.isNull(redisUser)) {
                //token有效,但redis数据被删除
                if (!StringUtils.isEmpty(token)) {
                    List<String> list = new ArrayList<>();
                    list.add(token);
                    eamUser.setTokenList(list);
                }
            } else {
                //缺少菜单信息
                eamUser.setTokenList(redisUser.getTokenList());
            }
        }
        SystemCacheUtil.cacheUserInfo(eamUser);
        if (self) {
            return Response.success(eamUser);
        } else {
            return Response.success(agentUser);
        }
    }

    @GetMapping("/getSingleUserInfo")
    @ApiOperation("获取单个用户基本信息(不包含权限信息)")
    public Response<AppUserVo> getSingleUserInfo(@RequestParam String account) {

        AppUserVo appUserVo = staffService.queryStaffInfoWithMerge(account);

        if (Objects.isNull(appUserVo)) {
            Response<AppUserVo> ok = Response.ok(new AppUserVo());
            ok.setDescription("不存在该账号信息:" + account);
            return ok;
        }
        return Response.success(appUserVo);
    }

    @GetMapping("/queryOrgVoListByAccount")
    @ApiOperation("获取单个用户可用组织信息List")
    public Response<List<OrgVo>> queryOrgVoListByAccount(@RequestParam String account) {

        List<OrgVo> orgVos = staffService.queryOrgVoListByAccount(account);

        return Response.success(orgVos);
    }

    @GetMapping("/queryAppSimpleInfoListByAccount")
    @ApiOperation("获取单个用户可切换水司信息")
    public Response<List<AppSimpleBean>> queryAppSimpleInfoListByAccount(@RequestParam String account) {

        List<AppSimpleBean> appSimpleInfoBeanList = staffService.queryAppSimpleInfoListByAccount(account);

        return Response.success(appSimpleInfoBeanList);
    }

    @ApiOperation(value = "外单位登录接口(移动端(去掉了验证码))")
    @PostMapping("/outStaffloginByMobile")
    public Response outStaffloginByMobile(@RequestBody OutStaffBean outStaffBean, HttpServletResponse response) {
        return staffService.outStafflogin(outStaffBean, response, false);
    }

    @ApiOperation(value = "外单位登录接口(PC)")
    @PostMapping("/outStafflogin")
    public Response outStafflogin(@RequestBody OutStaffBean outStaffBean, HttpServletResponse response) {
        return staffService.outStafflogin(outStaffBean, response);
    }

    @ApiOperation(value = "外单位手机号登录接口")
    @PostMapping("/outStaffloginByPhone")
    public Response outStaffloginByPhone(@RequestBody OutStaffBean outStaffBean, HttpServletResponse response) {
        return staffService.outStaffloginByPhone(outStaffBean, response);
    }

    @ApiOperation(value = "登录发送手机验证码")
    @GetMapping("/sendPhoneLoginMessage")
    public Response sendPhoneLoginMessage(@RequestParam @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误") String phone) {
        //校验手机号是否在系统中存在
        StaffBean staffBean = new StaffBean();
        staffBean.setPhone(phone);
        StaffBean staffBean1 = staffService.querySingleStaffInfo(staffBean);
        Assert.notNull(staffBean1, "不存在该手机号用户");
        return Response.success(outStaffService.sendPhoneMessage(phone, Constant.EAM_SERVICE_SYSTEM_LOGIN_VERIFYCODE, "登录EAM系统验证码:"));
    }

    @GetMapping("/getWorkFlowUserList")
    @ApiOperation("获取工作流用户")
    public List<WorkFlowUser> getWorkFlowUserList() {
        try {
            return staffService.getWorkFlowUserList();
        } catch (Exception e) {
            log.error("查询用户失败", e);
            return new ArrayList<>();
        }
    }

    @ApiOperation(value = "初始化拼音")
    @PutMapping("/resetPy")
    public Response resetPy(String id) {
        return Response.success(staffService.resetPy());
    }

    @ApiOperation(value = "校验密码接口")
    @PostMapping("/verifyStaffInfo")
    public Response verifyStaffInfo(@RequestBody OutStaffBean outStaffBean) {
        return staffService.verifyStaffInfo(outStaffBean);
    }

    @ApiOperation(value = "工作票校验密码接口")
    @PostMapping("/ticketVerifyStaffInfo")
    public Response ticketVerifyStaffInfo(@RequestBody OutStaffBean outStaffBean) {
        return staffService.verifyStaffInfo(outStaffBean);
    }

    @ApiOperation(value = "设置密码")
    @PutMapping("/resetPw")
    public Response resetPw(@RequestParam String account,
                               @RequestParam String password,
                               @RequestParam(required = false, value = "prePassword") String prePassword) {
        return staffService.resetPw(account, password, prePassword);
    }

    @ApiOperation(value = "忘记密码(待确认)")
    @PostMapping("/forgetPw")
    public Response forgetPw(@RequestBody ForgetPwDto forgetPwDto) {

        return staffService.forgetPw(forgetPwDto);
    }

    @ApiOperation(value = "忘记密码发送手机验证码")
    @GetMapping("/sendPhoneMessage")
    public Response sendPhoneMessage(@RequestParam @Pattern(regexp = "^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误") String phone) {
        //校验手机号是否在系统中存在
        StaffBean staffBean = new StaffBean();
        staffBean.setPhone(phone);
        StaffBean staffBean1 = staffService.querySingleStaffInfo(staffBean);
        Assert.notNull(staffBean1, "不存在该手机号用户");
        return Response.success(outStaffService.sendPhoneMessage(phone, "eam-service-system-forget-VerifyCode", "修改EAM系统密码验证码:"));
    }

    @ApiOperation(value = "退出登录")
    @GetMapping("/signOut")
    public Response signOut(HttpServletRequest request, HttpServletResponse response) throws IOException {

        String token = request.getHeader(Constant.JWT_TOKEN);

        String t_account = SystemCacheUtil.verifyToken(token);

        //清理掉redis用户数据中token
        EamUser redisUser = SystemCacheUtil.getRedisUser(t_account);

        if (!Objects.isNull(redisUser)) {
            List<String> tokenList = redisUser.getTokenList();
            if (CollectionUtils.isNotEmpty(tokenList)) {
                tokenList.remove(token);
                redisUser.setTokenList(null);
                SystemCacheUtil.cacheUserInfo(redisUser);
            }
        }
        // 如果是竹云，使用竹云
        if (Constant.CasType.IAM.equals(casType)) {
            // log.info("auth 重定向竹云logout页面:{}", iamLogoutUrl);
            // 登出时不进行全局登出，所以不进行任何处理
            // response.setHeader("redirecturl", iamLogoutUrl);
            // response.setStatus(HttpStatus.FOUND.value());
            log.info("auth 竹云 清除本地缓存");
        } else {
            log.info("单点登录退出地址:{},清理token:{}", logoutUrl, token);
            if (StringUtils.isNotEmpty(logoutUrl)) {
                //调用清理单点登录退出接口 logoutUrl
                Map cond = new HashMap();
                cond.put("loginName", t_account);
                cond.put("token", "");
                try {
                    String s = httpClient.doGet(logoutUrl, cond);
                    log.info("单点登录退出系统返回:{}", s);
                    JSONObject jsonObject = JSONObject.parseObject(s);
                    if (jsonObject != null) {
                        return Response.ok(jsonObject.getString("description"));
                    }
                } catch (Exception e) {
                    log.error("单点登录退出接口失败:{},参数:{}", logoutUrl, JSON.toJSONString(cond));
                }
            }
        }
        return Response.ok("清理成功");
    }

    @ApiOperation(value = "登陆图形验证码")
    @GetMapping("/verifyCode")
    public void verifyCode(HttpServletRequest request, HttpServletResponse response) {
        IVerifyCodeGen iVerifyCodeGen = new SimpleCharVerifyCodeGenImpl();
        try {
            //设置长宽
            VerifyCode verifyCode = iVerifyCodeGen.generate(80, 28);
            String code = verifyCode.getCode();
            log.info(code);
            //存入redis 当前客户端ip:验证码
            String verity_code_exp = getConfig().getOrDefault("verity_code_exp", "120");
            RedisUtils.hset(Constant.EAM_SERVICE_AUTH_VERIFYCODE, IpUtil.getIpAddr(request), code, Integer.parseInt(verity_code_exp));
            //将VerifyCode绑定session
            request.getSession().setAttribute("VerifyCode", code);
            //设置响应头
            response.setHeader("Pragma", "no-cache");
            //设置响应头
            response.setHeader("Cache-Control", "no-cache");
            //在代理服务器端防止缓冲
            response.setDateHeader("Expires", 0);
            //设置响应内容类型
            response.setContentType("image/jpeg");
            response.getOutputStream().write(verifyCode.getImgBytes());
            response.getOutputStream().flush();
        } catch (IOException e) {
            log.info("", e);
        }
    }

    @ApiOperation(value = "获取公钥")
    @GetMapping("/getPublicKey")
    public Response<String> getPublicKey() {
        return Response.ok(MyRSAUtil.genKeyPair().get(0));
    }

    @ApiOperation(value = "加密数据")
    @PostMapping("/encrypt")
    public Response<String> encrypt(@RequestBody Map<String, String> cond) {
        return Response.ok(MyRSAUtil.encrypt(cond.get("str"), MyRSAUtil.genKeyPair().get(0)));
    }

    @ApiOperation(value = "解密数据")
    @PostMapping("/decrypt")
    public Response<String> decrypt(@RequestBody Map<String, String> cond) {
        return Response.ok(MyRSAUtil.decrypt(cond.get("str")));
    }

    /**
     * 第三方系统获取token用于登录，并返回一个token，账号为配置的账号
     * @param cond 包括一个code，里面放appId，需要在配置项中配置
     * @return token，60s过期
     */
    @ApiOperation(value = "获取token")
    @PostMapping("/getToken")
    public Response<String> getToken(@RequestBody Map<String, String> cond) {
        String code = MyRSAUtil.decrypt(cond.get("code"));
        if (StringUtils.isEmpty(code)) {
            return Response.fail("编码不能为空");
        }
        Map<String, String> appIdMap = ConfigInfoTool.getConfigByCode("system", "appId");
        String account = appIdMap.get(code);
        if (StringUtils.isEmpty(account)) {
            return Response.fail("无效授权");
        }
        Map<String, String> map = new HashMap<>();
        map.put(Constant.ACCOUNT, account);
        map.put(Constant.USERNAME, account);
        String token = JWTUtils.getToken(map, 60);
        return Response.ok(token);
    }

    Map<String, String> getConfig() {
        return ConfigInfoTool.getConfigByCode("system", "system_login_config");
    }


    @ApiOperation(value = "修改人员名称多语言")
    @GetMapping("/changeUserLang")
    public Response<String> changeUserLang(@RequestParam String acount, @RequestParam String lang) {

        ADOConnection.runTask( factory -> {
            LangUserOrgConvertMapper mapper = factory.getMapper(LangUserOrgConvertMapper.class);
            mapper.deleteByParamId(acount);
            Map<String, String> langmap = FastJsonUtils.getJsonToBean(lang, Map.class);
            Set<String> keySet = langmap.keySet();
            List<LangUserOrgConvert> insertList =new ArrayList();
            for (String key : keySet) {
                LangUserOrgConvert ob = new LangUserOrgConvert();
                ob.setId(CodeTools.getCode32());
                ob.setParamId(acount);
                ob.setUserOrgType("user");
                ob.setLangType(key);
                ob.setLangValue(langmap.get(key));
                insertList.add(ob);
            }
            mapper.batchInsert(insertList);
            return null;
        }, void.class);

        return Response.ok();
    }

    @ApiOperation(value = "获取人员名称多语言")
    @GetMapping("/getUserLang")
    public Response getUserLang(String acount) {

        HashMap resultmap = ADOConnection.runTask( factory -> {
            LangUserOrgConvertMapper mapper = factory.getMapper(LangUserOrgConvertMapper.class);
            List<LangUserOrgConvert> list = mapper.queryByParamId(acount);
            HashMap<String, String> map = new HashMap<>();
            for (LangUserOrgConvert langUserOrgConvert : list) {
                map.put(langUserOrgConvert.getLangType(), langUserOrgConvert.getLangValue());
            }
            return map;
        }, HashMap.class);

        return Response.ok(resultmap);
    }

}
